<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Workflow DAG</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
    <script src="https://gw.alipayobjects.com/os/lib/antv/g6/3.7.1/dist/g6.min.js"></script>
    <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.3/theme-chalk/index.min.css">
    <script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.3/index.min.js"></script>

    <script>
        let pathContext = location.pathname.substr(0, location.pathname.lastIndexOf('/'));
        const meta = axios.create({
            baseURL: pathContext + '/v1/meta',
            timeout: 1000,
            headers: {'X-Custom-Header': 'foobar'}
        });
        meta.interceptors.response.use(response => {
            if (response.status < 200 || 300 <= response.status) {
                return Promise.reject(response.error);
            }
            let result = response.data;
            if (result.code !== '0') {
                return Promise.reject(result.msg);
            }
            return Promise.resolve(result.data);
        });
    </script>

    <script>
        /**
         * 对Date的扩展，将 Date 转化为指定格式的String
         * 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符，
         * 年(y)可以用 1-4 个占位符，毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
         * 例子：
         * (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
         * (new Date()).Format("yyyy-M-d h:m:s.S")      ==> 2006-7-2 8:9:4.18
         *
         * @param fmt
         * @returns {string}
         */
        Date.prototype.format = function (fmt) { //author: meizz
            let o = {
                "M+": this.getMonth() + 1,                 //月份
                "d+": this.getDate(),                    //日
                "h+": this.getHours(),                   //小时
                "m+": this.getMinutes(),                 //分
                "s+": this.getSeconds(),                 //秒
                "q+": Math.floor((this.getMonth() + 3) / 3), //季度
                "S": this.getMilliseconds()             //毫秒
            };
            if (/(y+)/.test(fmt))
                fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
            for (let k in o)
                if (new RegExp("(" + k + ")").test(fmt))
                    fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
            return fmt;
        };
    </script>
</head>
<body style="background: #f7eeea">

<div style="width: 1200px; height: 900px; margin: 10px auto; background: #FFFFFF; border: 1px solid #EEEEEE">
    <div id="container"></div>
    <div id="listApp" style="display: none">
        <el-table :data="list" border>
            <el-table-column prop="id" label="ID" width="80"></el-table-column>
            <el-table-column prop="name" label="名称">
                <template slot-scope="scope">
                    <a :href="'?id=' + scope.row.id">{{scope.row.name}}</a>
                </template>
            </el-table-column>
            <el-table-column prop="notifier" label="通知类型" width="80"></el-table-column>
            <el-table-column prop="remark" label="说明"></el-table-column>
            <el-table-column prop="createdAt" label="创建时间" width="160"></el-table-column>
            <el-table-column prop="updatedAt" label="更新时间" width="160"></el-table-column>
        </el-table>
    </div>
</div>

<script>
    function loadList() {
        console.log('listApp')
        window.listApp = new Vue({
            el: '#listApp',
            data: {
                list: []
            },
            created() {
                this.getList();
                this.$nextTick(() => {
                    this.$el.style.display = 'block';
                })
            },
            methods: {
                getList() {
                    meta.get('/workflows').then(list => {
                        list = list || [];
                        list.forEach(w => {
                            if (w.createdAt)
                                w.createdAt = this.datetime(w.createdAt)
                            w.updatedAt = this.datetime(w.updatedAt)
                        })
                        this.list = list;
                    }).catch(e => {
                        console.error(e)
                    });
                },
                datetime(v) {
                    if (!v) return '';
                    return new Date(v).format('yyyy-MM-dd hh:mm:ss')
                }
            }
        })
    }

    function loadById() {
        let nodesReq = meta.get('/nodes');
        let workflowReq = meta.get('/workflow/' + id);
        workflowReq.then((workflow) => {
            draw(buildData(workflow))
        }).catch(e => {
            console.error(e)
        });
    }

    function buildNodeMap(nodes = []) {
        let map = new Map();
        nodes.forEach((node) => {
            map.set(node.id, node)
        })
        return map;
    }

    function buildData(workflow) {
        let data = {nodes: [], edges: []};
        (workflow.nodes || []).forEach(n => {
            data.nodes.push({
                id: n.nodeName,
                label: n.nodeName
            });
        });
        (workflow.edges || []).forEach(edge => {
            data.edges.push({
                source: edge.fromNode,
                target: edge.toNode
            })
        });
        return data;
    }

    function draw(data) {
        const graph = new G6.Graph({
            container: 'container',
            width: 1200,
            height: 900,
            controlPoints: false,
            modes: {
                default: ['drag-canvas', 'drag-node', 'zoom-canvas'],
            },
            layout: {
                type: 'dagre',
                nodeSize: [80, 60],
                nodesep: 40,
                ranksep: 40,
            },
            animate: true,
            defaultNode: {
                size: [80, 60],
                type: 'ellipse',
                style: {
                    lineWidth: 2,
                    stroke: '#5B8FF9',
                    fill: '#C6E5FF',
                },
            },
            defaultEdge: {
                type: 'cubic',
                style: {
                    radius: 20,
                    offset: 45,
                    endArrow: {
                        path: 'M 0,0 L 8,4 L 8,-4 Z',
                        fill: '#e8b69d',
                    },
                    lineWidth: 2,
                },
                size: 2,
                color: '#f67135',
            },
            nodeStateStyles: {
                selected: {
                    stroke: '#d9d9d9',
                    fill: '#5394ef',
                },
            },
        });
        graph.data(data);
        graph.render();
    }

    let url = new URL(location.href);
    let id = url.searchParams.get('id')
    if (id) {
        loadById();
    } else {
        loadList();
    }
</script>

</body>
</html>
